package com.googlecode.yami;

import javax.swing.*;

import com.mysql.jdbc.ResultSetMetaData;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;

public class ConsoleComponent extends JComponent implements ActionListener {

    private TabHeaderComponent thc;
    private int place;
    private JLabel commandLabel;
    private JTextField in;
    private JTextArea out;
    private JScrollPane jspOut;
    private JButton submit;
    private JButton clear;
    private JButton clearConsole;
    private JPanel buttonPanel;
    private JPanel top;
    private Connection conn;
    private Font font = new Font("Monospaced", Font.PLAIN, 14);

    ConsoleComponent(final Connection srvConn) {

	// pass the connection
	conn = srvConn;

	setLayout(new BorderLayout());

	// create and place the input box and the button to the top panel
	top = new JPanel();
	top.setLayout(new BoxLayout(top, BoxLayout.Y_AXIS));

	// input text
	commandLabel = new JLabel("SQL Command: ");

	// the input box
	in = new JTextField();
	in.setFocusable(true);
	top.add(commandLabel);
	top.add(in);

	// buttons
	submit = new JButton("Submit");
	clear = new JButton("Clear");
	clearConsole = new JButton("Clear Console");

	// adding the action listener for submit and clear buttons
	submit.addActionListener(this);
	clear.addActionListener(this);
	clearConsole.addActionListener(this);

	// shortcuts
	submit.setMnemonic(KeyEvent.VK_S);
	clear.setMnemonic(KeyEvent.VK_C);
	clearConsole.setMnemonic(KeyEvent.VK_R);

	// button panel
	buttonPanel = new JPanel();
	buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
	buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
	buttonPanel.add(Box.createHorizontalGlue());
	buttonPanel.add(submit);
	buttonPanel.add(Box.createRigidArea(new Dimension(15, 0)));
	buttonPanel.add(clear);
	buttonPanel.add(Box.createRigidArea(new Dimension(15, 0)));
	buttonPanel.add(clearConsole);
	buttonPanel.setPreferredSize(new Dimension(0, 40));
	top.add(buttonPanel);

	// the output box
	out = new JTextArea();
	out.setFocusable(false);

	// disable editing on the output
	out.setEditable(false);
	out.setBackground(Color.gray);
	out.setFont(font);
	jspOut = new JScrollPane(out);

	// put everything together, with BorderLayout
	add(top, BorderLayout.NORTH);
	add(jspOut);

	// adding the new component to the tabbed pane
	MainWindow.JTP.addTab("MySQL Console Emulator", this);
	place = MainWindow.JTP.indexOfComponent(this);

	// adding the tab header component for the created tab
	thc = new TabHeaderComponent(MainWindow.JTP);
	MainWindow.JTP.setTabComponentAt(place, thc);

	// by default focus is on input field;
	in.requestFocus();

	// default button <Return>
	getRootPane().setDefaultButton(submit);
    }

    public void actionPerformed(ActionEvent arg0) {
	Object source = arg0.getSource();
	if ((JButton) source == submit) {

	    // passing the value of JTexarea in
	    String cResult = "";
	    String result = "";
	    String query = in.getText();
	    int columnCount;

	    // exit on exit :P
	    if (query.equals("exit") || query.equals("quit")) {
		Component current = MainWindow.JTP.getSelectedComponent();
		MainWindow.JTP.remove(current);
	    } else {

		// variables for max lenght of table entries
		int[] maxColWidth;
		int cLength;
		int maxLength = 0;

		// initialize the result set
		ResultSet answer = null;
		ResultSetMetaData answerMeta = null;

		// counting the returned row in the query
		int nmbOfRows = 0;

		// executing the query
		answer = Connect.execSQL(conn, query);

		try {

		    // it's possible that some valid queries are returning
		    // without
		    // answer, example: USE databaseName, so we need to check
		    // the
		    // result set because the answer.getString(1)
		    if (answer != null) {
			while (answer.next()) {
			    nmbOfRows++;
			}

			// after counting the returned rows we need to set the
			// result set's cursor to the beginning of the result
			// set
			answer.first();

			// fetch MetaData to determinate the number of returned
			// columns
			answerMeta = (ResultSetMetaData) answer.getMetaData();

			// determinate the number of columns in the returned
			// ResultSet
			columnCount = answerMeta.getColumnCount();
			maxColWidth = new int[columnCount];

			// determinating the longest string in each column;
			for (int j = 1; j <= columnCount; j++) {
			    for (int i = 0; i < nmbOfRows; i++) {
				cLength = answer.getString(j).length();
				// add some max length, above do not format, takes to much time
				if (cLength > 1000) {
				    maxColWidth[j - 1] = answer.getMetaData().getColumnLabel(j).length();
				} else {
				    if (cLength > maxColWidth[j - 1])
					maxColWidth[j - 1] = cLength;
				    if (answerMeta.getColumnLabel(j).length() > maxColWidth[j - 1])
					maxColWidth[j - 1] = answerMeta.getColumnLabel(j).length();
				}
				answer.next();
			    }
			    maxLength += maxColWidth[j - 1];
			    answer.first();
			}

			// top wrapper
			result = "+-";
			for (int i = 1; i <= columnCount; i++)
			    result += wrap(maxColWidth[i - 1]);

			// displaying column names
			result += "\n| ";
			for (int i = 1; i <= columnCount; i++) {
			    result += answerMeta.getColumnLabel(i) + fill(answerMeta.getColumnLabel(i), maxColWidth[i - 1]) + " |";
			}
			result += "\n";

			// column wrapper
			result += "+-";
			for (int i = 1; i <= columnCount; i++)
			    result += wrap(maxColWidth[i - 1]);

			out.append(result);

			// displaying the result set
			for (int i = 0; i < nmbOfRows; i++) {
			    cResult = "\n| ";
			    for (int c = 1; c <= columnCount; c++) {
				cResult += answer.getString(c) + fill(answer.getString(c), maxColWidth[c - 1]) + " |";
			    }
			    result += cResult + "\n";
			    out.append(cResult);
			    cResult = "";
			    if (!answer.next())
				break;
			}

			result = "\n";
			// bottom wrapper
			result += "+-";
			for (int i = 1; i <= columnCount; i++)
			    result += wrap(maxColWidth[i - 1]);

			// additional information about the query
			result += "\n" + nmbOfRows + " rows processed. \n\n";

			in.setCaretPosition(in.getText().length());
		    }
		} catch (SQLException ex) {
		    // handle any errors
		    System.out.println("Error while executing the MySQL statement.");
		    System.out.println("SQLException: " + ex.getMessage());
		    System.out.println("SQLState: " + ex.getSQLState());
		    System.out.println("VendorError: " + ex.getErrorCode());
		}

		// passing the result to JTextarea out
		out.append(result);

		// clearing the input
		in.setText("");
	    }
	} else if ((JButton) source == clear) {
	    in.setText("");
	} else if ((JButton) source == clearConsole) {
	    out.setText("");
	} else {
	    out.setText("Whoops... an error occured. O.o\n");
	}
    }

    // generate mysql-like console frames
    private String wrap(int colLength) {
	String wrap = "";

	for (int i = 0; i < colLength; i++)
	    wrap += "-";

	return wrap + "-+";
    }

    // generating spaces after shorter strings
    private String fill(String str, int maxLength) {
	int length = str.length();
	String fill = "";

	while (length++ < maxLength)
	    fill += " ";

	return fill;
    }

}
